package sh.grapendaal.tsuushin.module.uno.engine.service.impl;

import java.util.ArrayList;
import java.util.List;

import sh.grapendaal.tsuushin.module.uno.engine.domain.Player;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.Achievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.CommandAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.BabysFirstStepAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.IGot99ProblemsButAStackAintOneAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.IMightNeedThisLaterAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.ImDoingItForTheAchievementAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.ItsMyWayAndTheHighwayAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.ItsMyWayOrTheHighwayAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.LastDitchEffortAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.LookAgainTheCardIsNowDiamondsAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.MessageComingInFromAboveAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.OhNoYouDontAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.domain.achievement.impl.ThatSoundsBackwardsAchievement;
import sh.grapendaal.tsuushin.module.uno.engine.dto.GameState;
import sh.grapendaal.tsuushin.module.uno.engine.event.CommandEvent;
import sh.grapendaal.tsuushin.module.uno.engine.event.GameEvent;
import sh.grapendaal.tsuushin.module.uno.engine.event.dispatcher.GameEventDispatcher;
import sh.grapendaal.tsuushin.module.uno.engine.event.listener.CommandEventListener;
import sh.grapendaal.tsuushin.module.uno.engine.event.listener.GameEventListener;
import sh.grapendaal.tsuushin.module.uno.engine.service.AchievementService;
import sh.grapendaal.tsuushin.module.uno.engine.service.PlayerService;

/*
 * Some ideas for extra achievements:
 * - Rainbow completionist: player one plays three cards of different color, player two plays the same rank of the missing color
 */
public class AchievementServiceImpl extends GameEventDispatcher implements AchievementService {
	private static final List<CommandAchievement> COMMAND_EVENT_ACHIEVEMENTS = new ArrayList<CommandAchievement>();
	static {
		COMMAND_EVENT_ACHIEVEMENTS.add(new LookAgainTheCardIsNowDiamondsAchievement());
	}
	
	private static final List<Achievement> GAME_EVENT_CARD_PLAY_ACHIEVEMENTS = new ArrayList<Achievement>();
	static {
		GAME_EVENT_CARD_PLAY_ACHIEVEMENTS.add(new BabysFirstStepAchievement());
		GAME_EVENT_CARD_PLAY_ACHIEVEMENTS.add(new ThatSoundsBackwardsAchievement());
		GAME_EVENT_CARD_PLAY_ACHIEVEMENTS.add(new IGot99ProblemsButAStackAintOneAchievement());
		GAME_EVENT_CARD_PLAY_ACHIEVEMENTS.add(new MessageComingInFromAboveAchievement());
		GAME_EVENT_CARD_PLAY_ACHIEVEMENTS.add(new ItsMyWayOrTheHighwayAchievement());
		GAME_EVENT_CARD_PLAY_ACHIEVEMENTS.add(new ItsMyWayAndTheHighwayAchievement());
		GAME_EVENT_CARD_PLAY_ACHIEVEMENTS.add(new OhNoYouDontAchievement());
		GAME_EVENT_CARD_PLAY_ACHIEVEMENTS.add(new LastDitchEffortAchievement());
	}
	
	private static final List<Achievement> GAME_EVENT_CARD_DRAW_ACHIEVEMENTS = new ArrayList<Achievement>();
	static {
		GAME_EVENT_CARD_DRAW_ACHIEVEMENTS.add(new ImDoingItForTheAchievementAchievement());
		GAME_EVENT_CARD_DRAW_ACHIEVEMENTS.add(new IMightNeedThisLaterAchievement());
	}
	
	private PlayerService playerService;
	private final AchievementServiceCommandEventListener commandEventListener = new AchievementServiceCommandEventListener();
	private final AchievementServiceGameEventListener gameEventListener = new AchievementServiceGameEventListener();
	
	public AchievementServiceImpl(PlayerService playerService) {
		this.playerService = playerService;
	}
	
	@Override
	public CommandEventListener getCommandEventListener() {
		return this.commandEventListener;
	}

	@Override
	public GameEventListener getGameEventListener() {
		return this.gameEventListener;
	}
	
	private void checkGameAchievements(List<Achievement> achievements, GameState gameState) {
		for (Achievement achievement : achievements) {
			Player player = this.playerService.getPlayerByNickname(gameState.getCurrentPlayer().getNickname());
			if (!hasAchievement(player, achievement) && achievement.isEarned(gameState)) {
				dispatchAchievementUnlocked(gameState, achievement);
			}
		}
	}
	
	private void checkCommandAchievements(CommandEvent event) {
		for (CommandAchievement achievement : COMMAND_EVENT_ACHIEVEMENTS) {
			if (!hasAchievement(event.getPlayer(), achievement) && achievement.isEarned(event)) {
				dispatchAchievementUnlocked(null, achievement);
			}
		}
	}
	
	private boolean hasAchievement(Player player, Achievement achievement) {
		return player.getUnlockedAchievements().contains(achievement);
	}

	private class AchievementServiceCommandEventListener implements CommandEventListener {
		@Override
		public void onPlayerJoin(CommandEvent event) {
		}

		@Override
		public void onPlayerLeave(CommandEvent event) {
		}

		@Override
		public void onGameStart(CommandEvent event) {
		}

		@Override
		public void onGameStop(CommandEvent event) {
		}

		@Override
		public void onCardPlay(CommandEvent event) {
			checkCommandAchievements(event);
		}

		@Override
		public void onCardDraw(CommandEvent event) {
		}

		@Override
		public void onCardPass(CommandEvent event) {
		}
	}
	
	private class AchievementServiceGameEventListener implements GameEventListener {
		@Override
		public void onPlayerJoin(GameEvent event) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onPlayerLeave(GameEvent event) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onGameStart(GameEvent event) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onGameStop(GameEvent event) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onGameEnd(GameEvent event) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onCardPlay(GameEvent event) {
			checkGameAchievements(GAME_EVENT_CARD_PLAY_ACHIEVEMENTS, event.getGameState());
		}

		@Override
		public void onCardDraw(GameEvent event) {
			checkGameAchievements(GAME_EVENT_CARD_DRAW_ACHIEVEMENTS, event.getGameState());
		}

		@Override
		public void onCardPass(GameEvent event) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onTurnStart(GameEvent event) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onTurnSkip(GameEvent event) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onTurnEnd(GameEvent event) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onAchievementUnlock(GameEvent event, Achievement achievement) {
			// Do nothing.
		}
	}
}
